package com.bobi.tfca.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bobi.tfca.dao.MemberDao;
import com.bobi.tfca.model.constant.MailConstant;
import com.bobi.tfca.model.constant.RedisConstant;
import com.bobi.tfca.model.constant.ResourcePathConstant;
import com.bobi.tfca.model.entity.*;
import com.bobi.tfca.model.enums.MemberStatusEnum;
import com.bobi.tfca.model.vo.MemberProfileVO;
import com.bobi.tfca.model.vo.MemberVO;
import com.bobi.tfca.service.*;
import com.bobi.tfca.utils.CosUtils;
import com.bobi.tfca.utils.MailUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
import java.util.List;

/**
 * 会员服务层实现
 *
 * @author 李文发
 * @date 2024/4/3
 */
@Service
@Slf4j
public class MemberServiceImpl extends ServiceImpl<MemberDao, MemberEntity> implements MemberService {

    @Autowired
    private MemberDao memberDao;
    @Autowired
    private RoleService roleService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private MemberProfileService memberProfileService;
    @Autowired
    private GroupMemberService groupMemberService;
    @Autowired
    private MailUtil mailUtil;
    @Autowired
    private MenuService menuService;

    @Override
    public MemberVO getMemberById(Integer memberId) {
        MemberEntity member = this.getById(memberId);
        if (member == null) {
            return null;
        }
        MemberVO vo = MemberEntity.ofMemberEntity(member);
        // 设置成员角色
        RoleEntity role = roleService.getById(member.getRoleId());
        vo.setRole(role.getPosition());
        return vo;
    }

    /**
     * 注销用户为离会状态，删除redis的token，发送电子邮件
     * 会员相关信息置空，避免再次申请后，出现同样的账号，导致异常
     */
    @Override
    public Boolean removeAssMember(Integer memberId) {
        // 注销用户为离会状态
        // TODO 暂时只置空MembrEntity的电话号码，而不置空MemberProfileEntity的号码，所以MemberProfileEntity里电话号码不能唯一
        // 按理来说应该在MemberEntity里添加一个account账号属性
        LambdaUpdateWrapper<MemberEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MemberEntity::getMemberId, memberId)
                .set(MemberEntity::getMemberStatus, MemberStatusEnum.EXIT.getCode())
                .set(MemberEntity::getTelephone, null);
        this.update(updateWrapper);

        // 设置退会时间
        memberProfileService.update(new LambdaUpdateWrapper<MemberProfileEntity>()
                .eq(MemberProfileEntity::getMemberId, memberId)
                .set(MemberProfileEntity::getExitDate, LocalDate.now()));

        // 把用户从所在的群里剔除
        boolean remove = groupMemberService.remove(new LambdaQueryWrapper<GroupMemberEntity>()
                .eq(GroupMemberEntity::getMemberId, memberId));

        // 删除redis的token
        stringRedisTemplate.delete(RedisConstant.USER_JWT_PREFIX + memberId);
        //  发送电子邮件
        MemberEntity member = this.getById(memberId);
        String email = member.getEmail();
        String memberName = member.getMemberName();
        String mailText = String.format(MailConstant.QUIT_ASS_MAIL, memberName);
        mailUtil.sendSimpleTextMail(email, MailConstant.DEFAULT_MAIL_SUBJECT, mailText, null);
        return true;
    }

    @Override
    public List<MemberVO> findAllStillMembers() {
        List<MemberEntity> entities = memberDao.listStillMembers();
        if (entities != null && entities.size() > 0) {
            return entities.stream().map(this::getStillMemberVO).toList();
        }
        return new ArrayList<>();
    }

    @NotNull
    private MemberVO getStillMemberVO(MemberEntity it) {
        MemberVO memberVO = MemberEntity.ofMemberEntity(it);
        // 设置角色
        RoleEntity role = roleService.getById(it.getRoleId());
        memberVO.setRole(role.getPosition());
        // 设置leavewords内容为空
        memberVO.setLeaveWords(null);

        MemberProfileEntity profile = memberProfileService.getOne(new LambdaQueryWrapper<MemberProfileEntity>().eq(MemberProfileEntity::getMemberId, it.getMemberId()));
        // 设置入会时间
        memberVO.setEntryDate(profile.getEntryDate());
        // 设置会龄 = 当前时间 - 入会时间
        LocalDate previousDate = profile.getEntryDate();
        LocalDate currentDate = LocalDate.now();
        String memberAge = calculatePeriod(previousDate, currentDate);
        memberVO.setMemberAge(memberAge);
        return memberVO;
    }

    @NotNull
    private static String calculatePeriod(LocalDate previousDate, LocalDate currentDate) {
        Period period = Period.between(previousDate, currentDate);
        int years = period.getYears();
        int months = period.getMonths();
        int days = period.getDays();
        String memberAge = "";
        if (years > 0) {
            int totalDays = days + months * 30 + years * 365;
            double betweenPeriod = totalDays / 365.0;
            double roundedYears = Math.round(betweenPeriod * 10) / 10.0; // 保留一位小数
            memberAge = roundedYears + "年";
        } else if (months > 0) {
            int totalDays = days + months * 30;
            double betweenPeriod = totalDays / 30.0;
            double roundedMonths = Math.round(betweenPeriod * 10) / 10.0; // 保留一位小数
            memberAge = roundedMonths + "月";
        } else {
            memberAge = days + "天";
        }
        return memberAge;
    }

    @Override
    public List<MemberVO> findAllLeaveMembers() {
        LambdaQueryWrapper<MemberEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MemberEntity::getMemberStatus, MemberStatusEnum.EXIT.getCode());
        List<MemberEntity> entities = this.list(queryWrapper);
        if (entities != null && entities.size() > 0) {
            List<MemberVO> voList = entities.stream().map(this::getLeaveMemberVO).toList();
            return voList;
        }
        return new ArrayList<MemberVO>();
    }

    @NotNull
    private MemberVO getLeaveMemberVO(MemberEntity it) {
        MemberVO memberVO = MemberEntity.ofMemberEntity(it);
        // 设置角色
        RoleEntity role = roleService.getById(it.getRoleId());
        memberVO.setRole(role.getPosition());
        // 设置leavewords内容为空
        memberVO.setLeaveWords(null);

        MemberProfileEntity profile = memberProfileService.getOne(new LambdaQueryWrapper<MemberProfileEntity>().eq(MemberProfileEntity::getMemberId, it.getMemberId()));
        // 设置离会时间
        memberVO.setExitDate(profile.getExitDate());
        // 设置会龄 = 退会时间 - 入会时间
        LocalDate previousDate = profile.getEntryDate();
        LocalDate currentDate = profile.getExitDate();
        String memberAge = calculatePeriod(previousDate, currentDate);
        memberVO.setMemberAge(memberAge);
        // 设置会龄
        return memberVO;
    }

    @Override
    public Boolean changePwByPw(MemberEntity member, String oldPassword, String newPassword) {
        MemberEntity memberEntity = this.getById(member.getMemberId());
        if (memberEntity == null) {
            return false;
        }
        // 校验密码
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(oldPassword, memberEntity.getPassword())) {
            return false;
        }
        // 更改密码
        String newEncode = encoder.encode(newPassword);
        memberEntity.setPassword(newEncode);
        this.updateById(memberEntity);

        // 退出登录
        logout(memberEntity);
        return true;
    }

    @Override
    public Integer resetPassword(String account, String newPassword, String code) {
        MemberEntity registedMember = this.getOne(new LambdaQueryWrapper<MemberEntity>().eq(MemberEntity::getTelephone, account));
        // 如果不存在该用户
        if (registedMember == null) {
            return 2;
        }
        // 从redis中获得账号的，邮件验证码
        String redisCode = stringRedisTemplate.opsForValue().get(RedisConstant.USER_CAPTCHA_PREFIX + account);
        // 比对redisCode
        if (redisCode == null || (!redisCode.equals(code))) {
            return 1;
        }
        // 通过更改密码
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String newEncode = encoder.encode(newPassword);
        MemberEntity memberEntity = this.getOne(new LambdaQueryWrapper<MemberEntity>().eq(MemberEntity::getTelephone, account));
        memberEntity.setPassword(newEncode);
        this.updateById(memberEntity);
        return 0;
    }

    @Override
    public List<MemberVO> searchLeaveMemberByName(String searchContent) {
        // 模糊搜索
        LambdaQueryWrapper<MemberEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(MemberEntity::getMemberName, searchContent)
                .eq(MemberEntity::getMemberStatus, MemberStatusEnum.EXIT.getCode());
        List<MemberEntity> entities = this.list(queryWrapper);
        if (entities != null && entities.size() > 0) {
            List<MemberVO> voList = entities.stream().map(this::getLeaveMemberVO).toList();
            return voList;
        }
        return new ArrayList<MemberVO>();
    }

    @Override
    public List<MemberVO> searchStillMemberByName(String searchContent) {
        // 模糊搜索
        LambdaQueryWrapper<MemberEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(MemberEntity::getMemberName, searchContent)
                .eq(MemberEntity::getMemberStatus, MemberStatusEnum.NORMAL.getCode());
        List<MemberEntity> entities = this.list(queryWrapper);
        if (entities != null && entities.size() > 0) {
            List<MemberVO> voList = entities.stream().map(this::getStillMemberVO).toList();
            return voList;
        }
        return new ArrayList<>();
    }

    @Override
    public Boolean changeMemberRole(Integer memberId, String role) {
        MemberEntity member = this.getById(memberId);
        // 查询角色
        RoleEntity entity = roleService.getOne(new LambdaQueryWrapper<RoleEntity>().eq(RoleEntity::getPosition, role));
        if (entity == null) {
            return false;
        }
        member.setRoleId(entity.getRoleId());
        this.updateById(member);
        return true;
    }

    @Override
    public MemberProfileVO getProfileByMemberId(Integer memberId) {
        // 查询档案
        MemberProfileEntity profile = memberProfileService.getOne(new LambdaQueryWrapper<MemberProfileEntity>()
                .eq(MemberProfileEntity::getMemberId, memberId));
        MemberProfileVO profileVO = MemberProfileVO.ofMemberProfileEntity(profile);
        // 设置成员角色
        MemberEntity member = this.getById(memberId);
        RoleEntity role = roleService.getById(member.getRoleId());
        profileVO.setRole(role.getPosition());
        // 查询用户头像
        return profileVO;
    }

    /**
     * 用于登录返回
     */
    @Override
    public MemberVO getRoleAndMemberAge(MemberEntity member) {
        // 查询会员角色
        RoleEntity role = roleService.getById(member.getRoleId());
        MemberVO memberVO = MemberEntity.ofMemberEntity(member);
        memberVO.setRole(role.getPosition());
        // 计算会龄
        MemberProfileEntity profile = memberProfileService.getOne(new LambdaQueryWrapper<MemberProfileEntity>().eq(MemberProfileEntity::getMemberId, memberVO.getMemberId()));
        // 设置入会时间
        memberVO.setEntryDate(profile.getEntryDate());
        // 设置会龄 = 当前时间 - 入会时间
        LocalDate previousDate = profile.getEntryDate();
        LocalDate currentDate = LocalDate.now();
        String memberAge = calculatePeriod(previousDate, currentDate);
        memberVO.setMemberAge(memberAge);
        return memberVO;
    }

    /**
     * 得到当前用户的页面界面显示
     * <p>界面默认只显示非会员的，如果是理事的话就可以显示对应内容</p>
     * 虽然只有角色表也可以，但那样前端写的太死，非常的不好
     * <p>没有会员信息，代表会员没有jwttoken传入，也就是说会员还没有登陆过，将会员视作非会员用户。
     * </p>
     * @param member 当前用户
     * @return 元素列表
     */
    public List<String> getMemberMenus(MemberEntity member) {
        // 会员为空
        if (member == null) {
            // 未登录，则有注册功能和登录功能
            return List.of("fragment_user_ll_register", "fragment_user_ll_logout", "fragment_user_ll_forget_password");
        } else {
            MemberEntity entity = this.getById(member.getMemberId());
            Integer roleId = entity.getRoleId();
            List<String> menus = menuService.getRoleMenus(roleId);
            return menus;
        }
    }

    @Override
    public Boolean logout(MemberEntity member) {
        String key = RedisConstant.USER_JWT_PREFIX + member.getMemberId();
        stringRedisTemplate.delete(key);
        return true;
    }

    @Override
    public String updateMyHeadPhoto(MemberEntity member, MultipartFile file) {
        String url = "";
        try {
            url = CosUtils.uploadFile(file, ResourcePathConstant.IMAGE_PATH);

            this.update(new LambdaUpdateWrapper<MemberEntity>()
                    .eq(MemberEntity::getMemberId, member.getMemberId())
                    .set(MemberEntity::getPicture, url));
            // 档案也要修改
            memberProfileService.update(new LambdaUpdateWrapper<MemberProfileEntity>()
                    .eq(MemberProfileEntity::getMemberId, member.getMemberId())
                    .set(MemberProfileEntity::getPicture, url));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return url;
    }

    @Override
    public String getMemberByAccount(String account) {
        LambdaQueryWrapper<MemberEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MemberEntity::getTelephone, account)
                .eq(MemberEntity::getMemberStatus, MemberStatusEnum.NORMAL.getCode());
        MemberEntity member = this.getOne(queryWrapper);
        if (member != null) {
            return member.getEmail();
        } else {
            return null;
        }
    }
}